﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Creventive.Wpf.ShellFactory.Workspace.Primitives
{
    /// <summary>
    /// Represents a single item (application view container) in a workspace
    /// </summary>
    public class WorkspaceItem : Control
    {
        #region Static Fields/Constants

        /// <summary>
        /// Backing field for the ApplicationView dependency property
        /// </summary>
        public static readonly DependencyProperty ApplicationViewProperty = DependencyProperty.Register("ApplicationView", typeof(ApplicationView), typeof(WorkspaceItem), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, (s, e) => ((WorkspaceItem)s).OnApplicationViewChanged((ApplicationView)e.OldValue, (ApplicationView)e.NewValue)));
        private static readonly PropertyDescriptor TitlePropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ApplicationView.TitleProperty, typeof(ApplicationView));
        private static readonly PropertyDescriptor IconPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ApplicationView.IconProperty, typeof(ApplicationView));
        private static readonly PropertyDescriptor IsActivePropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ApplicationView.IsActiveProperty, typeof(ApplicationView));
        private static readonly DependencyPropertyKey IsActivePropertyKey = DependencyProperty.RegisterReadOnly("IsActive", typeof(bool), typeof(WorkspaceItem), new UIPropertyMetadata(false));
        /// <summary>
        /// Backing field for the IsActive dependency property
        /// </summary>
        public static readonly DependencyProperty IsActiveProperty = IsActivePropertyKey.DependencyProperty;
        private static readonly DependencyPropertyKey TitlePropertyKey = DependencyProperty.RegisterReadOnly("Title", typeof(object), typeof(WorkspaceItem), new UIPropertyMetadata(null));
        /// <summary>
        /// Backing field for the Title dependency property
        /// </summary>
        public static readonly DependencyProperty TitleProperty = TitlePropertyKey.DependencyProperty;
        private static readonly DependencyPropertyKey IconPropertyKey = DependencyProperty.RegisterReadOnly("Icon", typeof(ImageSource), typeof(WorkspaceItem), new UIPropertyMetadata(null));
        /// <summary>
        /// Backing field for the Icon dependency property
        /// </summary>
        public static readonly DependencyProperty IconProperty = IconPropertyKey.DependencyProperty;
        private static readonly DependencyPropertyKey WorkspaceItemPropertyKey = DependencyProperty.RegisterAttachedReadOnly("WorkspaceItem", typeof(WorkspaceItem), typeof(WorkspaceItem), new UIPropertyMetadata(null));
        /// <summary>
        /// Backing field for the WorkspaceItem dependency property
        /// </summary>
        public static readonly DependencyProperty WorkspaceItemProperty = WorkspaceItemPropertyKey.DependencyProperty;
        private static readonly DependencyPropertyKey WorkspacePropertyKey = DependencyProperty.RegisterReadOnly("Workspace", typeof(IWorkspace), typeof(WorkspaceItem), new UIPropertyMetadata(null));
        /// <summary>
        /// Backing field for the Workspace dependency property
        /// </summary>
        public static readonly DependencyProperty WorkspaceProperty = WorkspacePropertyKey.DependencyProperty;

        #endregion

        static WorkspaceItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(WorkspaceItem), new FrameworkPropertyMetadata(typeof(WorkspaceItem)));
            FocusableProperty.OverrideMetadata(typeof(WorkspaceItem), new FrameworkPropertyMetadata(false));
            IsTabStopProperty.OverrideMetadata(typeof(WorkspaceItem), new FrameworkPropertyMetadata(false));
        }

        /// <summary>
        /// Gets or sets the application view.
        /// </summary>
        /// <value>The application view.</value>
        [Bindable(true)]
        public ApplicationView ApplicationView
        {
            get { return (ApplicationView)this.GetValue(ApplicationViewProperty); }
            set { this.SetValue(ApplicationViewProperty, value); }
        }

        /// <summary>
        /// Gets the icon.
        /// </summary>
        /// <value>The icon.</value>
        public ImageSource Icon
        {
            get { return (ImageSource)this.GetValue(IconProperty); }
            private set { this.SetValue(IconPropertyKey, value); }
        }

        /// <summary>
        /// Gets a value indicating whether this item is active.
        /// </summary>
        /// <value><c>true</c> if this instance is active; otherwise, <c>false</c>.</value>
        public bool IsActive
        {
            get { return (bool)this.GetValue(IsActiveProperty); }
            private set { this.SetValue(IsActivePropertyKey, value); }
        }

        /// <summary>
        /// Gets an enumerator for logical child elements of this element.
        /// </summary>
        /// <value></value>
        /// <returns>An enumerator for logical child elements of this element.</returns>
        protected override IEnumerator LogicalChildren
        {
            get
            {
                if (this.ApplicationView != null)
                    yield return this.ApplicationView;
            }
        }

        /// <summary>
        /// Gets the title.
        /// </summary>
        /// <value>The title.</value>
        public object Title
        {
            get { return this.GetValue(TitleProperty); }
            private set { this.SetValue(TitlePropertyKey, value); }
        }

        /// <summary>
        /// Gets the workspace this item belongs to.
        /// </summary>
        /// <value>The workspace.</value>
        public IWorkspace Workspace
        {
            get { return (IWorkspace)this.GetValue(WorkspaceProperty); }
            internal set { this.SetValue(WorkspacePropertyKey, value); }
        }

        /// <summary>
        /// Gets the workspace item for the given application view.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <returns></returns>
        public static WorkspaceItem GetWorkspaceItem(ApplicationView obj)
        {
            return (WorkspaceItem)obj.GetValue(WorkspaceItemProperty);
        }

        private static void SetWorkspaceItem(ApplicationView obj, WorkspaceItem value)
        {
            obj.SetValue(WorkspaceItemPropertyKey, value);
        }

        private static void ClearWorkspaceItem(ApplicationView obj)
        {
            obj.ClearValue(WorkspaceItemPropertyKey);
        }

        /// <summary>
        /// Called when the ApplicationView property has changed.
        /// </summary>
        /// <param name="oldValue">The old value.</param>
        /// <param name="newValue">The new value.</param>
        protected virtual void OnApplicationViewChanged(ApplicationView oldValue, ApplicationView newValue)
        {
            if (oldValue == newValue)
                return;

            if (oldValue != null)
            {
                ClearWorkspaceItem(oldValue);
                this.ClearValue(IconPropertyKey);
                this.ClearValue(TitlePropertyKey);
                this.ClearValue(IsActivePropertyKey);
            }

            if (newValue != null)
            {
                SetWorkspaceItem(newValue, this);
                this.Icon = newValue.Icon;
                IconPropertyDescriptor.AddValueChanged(newValue, NotifyIconChanged);

                this.Title = newValue.Title;
                TitlePropertyDescriptor.AddValueChanged(newValue, NotifyTitleChanged);

                this.IsActive = newValue.IsActive;
                IsActivePropertyDescriptor.AddValueChanged(newValue, NotifyIsActiveChanged);
            }
        }

        private static void NotifyTitleChanged(object sender, EventArgs e)
        {
            ApplicationView view = (ApplicationView)sender;
            WorkspaceItem item = GetWorkspaceItem(view);
            if (item != null)
                item.Title = view.Title;
        }

        private static void NotifyIconChanged(object sender, EventArgs e)
        {
            ApplicationView view = (ApplicationView)sender;
            WorkspaceItem item = GetWorkspaceItem(view);
            if (item != null)
                item.Icon = view.Icon;
        }

        private static void NotifyIsActiveChanged(object sender, EventArgs e)
        {
            ApplicationView view = (ApplicationView)sender;
            WorkspaceItem item = GetWorkspaceItem(view);
            if (item != null)
                item.IsActive = view.IsActive;
        }
    }
}